﻿using System;
using Cesave.Application.Permisos.SynchronizationService;
using Cesave.Application.Permisos.SynchronizationService.Proxies.SynchronizationModule;
using Cesave.Infrastructure.CrossCutting.IoC;
using Cesave.Infrastructure.CrossCutting.Logging;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;

namespace Cesave.DistributedServices.PermisosModule.WindowsHost
{
    public class SynchronizationAgent
        : ISynchronizationAgent
    {
        #region Private properties

        PermisosCacheSyncAgent _permisosSynchronizationAgent;
        SyncStatistics _synchronizationStatistics;

        event EventHandler<SessionProgressEventArgs> SynchronizationProgressChanged;
        event EventHandler<SessionStateChangedEventArgs> SynchronizationSessionStateChanged;

        readonly object _objectLocker = new object();

        #endregion

        #region ISynchronizationAgent Members

        public void Synchronize()
        {
            try
            {
                _permisosSynchronizationAgent = new PermisosCacheSyncAgent();
                _permisosSynchronizationAgent.SessionProgress += Synchronization_SessionProgress;
                _permisosSynchronizationAgent.StateChanged += Synchronization_StateChanged;
                using (var synchronizationClient = new PermisosCacheSyncContractClient())
                {
                    _permisosSynchronizationAgent.RemoteProvider = new ServerSyncProviderProxy(synchronizationClient);
					PermisosCacheClientSyncProvider clientSyncProvider = (PermisosCacheClientSyncProvider)_permisosSynchronizationAgent.LocalProvider;
					clientSyncProvider.AddHandlers();
                    // Quitar el comentario una vez que se haya resulto la excepción (400) Bad Request.
                    _synchronizationStatistics = _permisosSynchronizationAgent.Synchronize();
                }
            }
            catch (SyncException ex)
            {
                var traceManager = IoCFactory.Resolve<ITraceManager>();
                traceManager.TraceCritical(ex.Message);
            }
        }

        public SyncSessionState SyncSessionState
        {
            get
            {
                return _permisosSynchronizationAgent.SessionState;
            }
        }

        event EventHandler<SessionStateChangedEventArgs> ISynchronizationAgent.SynchronizationSessionStateChanged
        {
            add
            {
                lock (_objectLocker)
                    SynchronizationSessionStateChanged += value;
            }
            remove
            {
                lock (_objectLocker)
                    SynchronizationSessionStateChanged -= value;
            }
        }

        event EventHandler<SessionProgressEventArgs> ISynchronizationAgent.SynchronizationProgressChanged
        {
            add
            {
                lock (_objectLocker)
                    SynchronizationProgressChanged += value;
            }
            remove
            {
                lock (_objectLocker)
                    SynchronizationProgressChanged -= value;
            }
        }

        public SyncStatistics SynchronizationStatistics
        {
            get
            {
                return _synchronizationStatistics;
            }
        }

        #endregion

        #region Event methods

        private void Synchronization_StateChanged(object sender, SessionStateChangedEventArgs e)
        {
            OnSynchronizationSessionStateChanged(new SessionStateChangedEventArgs(e.SessionState, e.SyncSession));
        }

        private void Synchronization_SessionProgress(object sender, SessionProgressEventArgs e)
        {
            OnSynchronizationProgressChanged(new SessionProgressEventArgs(e.SyncStage, e.PercentCompleted, e.BatchProgress));
        }

        #endregion

        #region Private methods

        private void OnSynchronizationSessionStateChanged(SessionStateChangedEventArgs e)
        {
            if (SynchronizationSessionStateChanged != null)
                SynchronizationSessionStateChanged(this, e);
        }

        private void OnSynchronizationProgressChanged(SessionProgressEventArgs e)
        {
            if (SynchronizationProgressChanged != null)
                SynchronizationProgressChanged(this, e);
        }

        #endregion

    }
}
